package com.google.code.sysarch.v4.graphical;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.IntBuffer;

import org.lwjgl.input.Keyboard;
import org.lwjgl.input.Mouse;
import org.lwjgl.opengl.Display;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.glu.GLU;

public class Renderer {

	Game game;
	
	public void setGame(Game g) {
		this.game = g;
	}
	
	/**
	 * Performs all rendering in the game
	 */
	public void renderScene() {
		float[] LightPosition = { 1f, 1f, 1f, 0f };
		GL11.glClear(GL11.GL_DEPTH_BUFFER_BIT | GL11.GL_STENCIL_BUFFER_BIT);
		GL11.glMatrixMode(GL11.GL_MODELVIEW);
		GL11.glLoadIdentity();
		GL11.glDisable(GL11.GL_LIGHTING);
		GL11.glDisable(GL11.GL_DEPTH_TEST);		
			
		GL11.glRotatef(game.xrot, 1, 0, 0);
		GL11.glRotatef(game.yrot, 0, 1, 0);
		GL11.glRotatef(game.zrot, 0, 0, 1);
		// Render the skybox
		game.sky.render();
		GL11.glTranslatef(game.xpos, game.ypos, game.zpos);
		// Render everything below the water level
		GL11.glEnable(GL11.GL_DEPTH_TEST);
		for (int i=0; i<game.fish.length; i++) game.fish[i].render();
		GL11.glClear(GL11.GL_DEPTH_BUFFER_BIT);
		
		// Reflections
		if (game.reflections) {
			double eqr[] = {0.0f,-1.0f, 0.0f, 0.0f};
			GL11.glColorMask(false, false, false, false);
			GL11.glDisable(GL11.GL_DEPTH_TEST);
			GL11.glEnable(GL11.GL_STENCIL_TEST);
			GL11.glStencilFunc(GL11.GL_ALWAYS, 1, 1);
			GL11.glStencilOp(GL11.GL_KEEP, GL11.GL_KEEP, GL11.GL_REPLACE);
			drawWater();
			GL11.glEnable(GL11.GL_DEPTH_TEST);
			GL11.glColorMask(true, true, true, true);
			GL11.glStencilFunc(GL11.GL_EQUAL, 1, 1);
			GL11.glStencilOp(GL11.GL_KEEP, GL11.GL_KEEP, GL11.GL_KEEP);
			GL11.glEnable(GL11.GL_CLIP_PLANE0);
			GL11.glClipPlane(GL11.GL_CLIP_PLANE0, LWJGLGameWindow.toDoubleBuffer(eqr));
			GL11.glPushMatrix();
				GL11.glScalef(1f, -1f, 1f);		
				GL11.glLight(GL11.GL_LIGHT0, GL11.GL_POSITION, LWJGLGameWindow.toFloatBuffer(LightPosition));
				GL11.glEnable(GL11.GL_LIGHTING);
				game.grid.renderShips();
				if (game.buoy != null) {
					game.buoy.translate(-20, 0, -20);
					game.buoy.render();
					game.buoy.translate(game.grid.getRealWidth() + 20, 0, -20);
					game.buoy.render();
				}
			GL11.glPopMatrix();
			GL11.glDisable(GL11.GL_CLIP_PLANE0);
			GL11.glDisable(GL11.GL_STENCIL_TEST);
			GL11.glDisable(GL11.GL_LIGHTING);
		} else {
			// Render everything above the water level
			GL11.glLight(GL11.GL_LIGHT0, GL11.GL_POSITION, LWJGLGameWindow.toFloatBuffer(LightPosition));
			GL11.glEnable(GL11.GL_LIGHTING);
			game.grid.renderShips();
			game.grid_enemy.renderShips();
			if (game.buoy != null) {
				game.buoy.translate(-20, 0, -20);
				game.buoy.render();
				game.buoy.translate(game.grid.getRealWidth() + 20, 0, -20);
				game.buoy.render();
			}
		}

		// Render the water				
		GL11.glEnable(GL11.GL_BLEND);		
		GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
		if (!game.reflections) GL11.glDepthMask(false);		
		drawWater();
		GL11.glBlendFunc(GL11.GL_ONE, GL11.GL_ONE);
		if (game.reflections) GL11.glDisable(GL11.GL_DEPTH_TEST);
		game.grid_enemy.renderGrid();		
		game.grid.renderGrid();
		if (game.reflections) GL11.glEnable(GL11.GL_DEPTH_TEST);		
		if (!game.reflections) GL11.glDepthMask(true);
		GL11.glDisable(GL11.GL_BLEND);		
		
		if (game.reflections) {
			// Render everything above the water level
			GL11.glLight(GL11.GL_LIGHT0, GL11.GL_POSITION, LWJGLGameWindow.toFloatBuffer(LightPosition));
			GL11.glEnable(GL11.GL_LIGHTING);			
			game.grid.renderShips();
			game.grid_enemy.renderShips();
			if (game.buoy != null) {
				game.buoy.translate(-20, 0, -20);
				game.buoy.render();
				game.buoy.translate(game.grid.getRealWidth() + 20, 0, -20);
				game.buoy.render();
			}
		}
		
		drawInterface();
		GL11.glFlush();		
		
		Display.update();		
	}
	
	public int getSelection() {
		int mx = (int) (((float) Mouse.getX() / game.window.getWidth()) * 1280);
		int my = 1024 - (int) (((float) Mouse.getY() / game.window.getHeight()) * 1024);
		if (game.gamemode == Game.GAMEMODE_PLACE_SHIPS) {
			for (int i=0; i<6; i++) {
				if (game.button_ship[i].isMouseOver(mx, my)) {
					return game.button_ship[i].getName();
				}
			}
		}		
		int[] viewport = new int[4];
		int[] buffer = new int[128];
		IntBuffer temp = ByteBuffer.allocateDirect(64).order(ByteOrder.nativeOrder()).asIntBuffer();
		GL11.glGetInteger(GL11.GL_VIEWPORT, temp);
		temp.get(viewport);
        temp = ByteBuffer.allocateDirect(2048).order(ByteOrder.nativeOrder()).asIntBuffer();
        GL11.glSelectBuffer(temp);
		GL11.glRenderMode(GL11.GL_SELECT);
		GL11.glInitNames();
		GL11.glPushName(0);
		GL11.glMatrixMode(GL11.GL_PROJECTION);
		GL11.glPushMatrix();
		GL11.glLoadIdentity();
		// This Creates A Matrix That Will Zoom Up To A Small Portion Of The Screen, Where The Mouse Is.
		GLU.gluPickMatrix(Mouse.getX(), Mouse.getY(), 1.0f, 1.0f, viewport);
		// Apply The Perspective Matrix
		GLU.gluPerspective(45.0f, (float)(viewport[2]-viewport[0]) / (float)(viewport[3]-viewport[1]), 0.1f, game.window.getFarSight());
		GL11.glMatrixMode(GL11.GL_MODELVIEW);
		GL11.glLoadIdentity();
		GL11.glRotatef(game.xrot, 1, 0, 0);
		GL11.glRotatef(game.yrot, 0, 1, 0);
		GL11.glRotatef(game.zrot, 0, 0, 1);
		GL11.glTranslatef(game.xpos, game.ypos, game.zpos);		
		GL11.glDisable(GL11.GL_LIGHTING);
		if (game.gamemode == Game.GAMEMODE_PLACE_SHIPS) {
			if (Keyboard.isKeyDown(Keyboard.KEY_K)) {
				game.grid.renderShips();
			} else {
				game.grid.renderGrid();
			}
		} else if (game.gamemode == Game.GAMEMODE_FIRING) {
			game.grid_enemy.renderGrid();
		}
		GL11.glMatrixMode(GL11.GL_PROJECTION);
		GL11.glPopMatrix();
		GL11.glMatrixMode(GL11.GL_MODELVIEW);
		int hits = GL11.glRenderMode(GL11.GL_RENDER);
        temp.get(buffer);
           
        int minZ = 0xffffffff;
        @SuppressWarnings("unused")
		int numNames = 0;
        int nameStore = 0;
        int index = 0;
        while (hits-- > 0) {	
        	int n = buffer[index++];
        	if (buffer[index] < minZ) {
        		minZ = buffer[index];
        		numNames = 0;
        		nameStore = index+2;
        	}
        	index += 2+n;
        }
        return buffer[nameStore];
	}
	
	private void drawWater() {
		game.watertex.bind();
		GL11.glBegin(GL11.GL_TRIANGLE_FAN);
			GL11.glNormal3f(0, 1, 0);		
			// Mitte
			GL11.glColor4f(1, 1, 1, 0.65f);			
			GL11.glTexCoord2f(0, 0);
			GL11.glVertex3f(0, 0, 0);
			// Ecken
			GL11.glColor4f(1, 1, 1, 0);
			GL11.glTexCoord2f(-8, -8);
			GL11.glVertex3f(-1000, 0, -1000);
			GL11.glTexCoord2f(-10, 0);
			GL11.glVertex3f(-1280, 0, 0);			
			GL11.glTexCoord2f(-8, 8);
			GL11.glVertex3f(-1000, 0, 1000);
			GL11.glTexCoord2f(0, 10);
			GL11.glVertex3f(0, 0, 1280);	
			GL11.glTexCoord2f(8, 8);			
			GL11.glVertex3f(1000, 0, 1000);
			GL11.glTexCoord2f(10, 0);
			GL11.glVertex3f(1280, 0, 0);			
			GL11.glTexCoord2f(8, -8);
			GL11.glVertex3f(1000, 0, -1000);
			GL11.glTexCoord2f(0, -10);
			GL11.glVertex3f(0, 0, -1280);
			GL11.glTexCoord2f(-8, -8);
			GL11.glVertex3f(-1000, 0, -1000);			
		GL11.glEnd();
	}
	
	public void drawInterface() {
		GL11.glMatrixMode(GL11.GL_PROJECTION);
		GL11.glPushMatrix();
			GL11.glLoadIdentity();
			GL11.glOrtho(0, 1280, 1024, 0, -1, 1);
			GL11.glMatrixMode(GL11.GL_MODELVIEW);
			GL11.glLoadIdentity();
			GL11.glDisable(GL11.GL_LIGHTING);
			GL11.glDisable(GL11.GL_DEPTH_TEST);
			GL11.glEnable(GL11.GL_ALPHA_TEST);
			GL11.glAlphaFunc(GL11.GL_GREATER, 0.5f);
			if (game.gamemode == Game.GAMEMODE_PLACE_SHIPS) {
				for (int i=0; i<6; i++) game.button_ship[i].render();
			}			
			game.mousecursor.render();
			GL11.glDisable(GL11.GL_ALPHA_TEST);
			GL11.glMatrixMode(GL11.GL_PROJECTION);
		GL11.glPopMatrix();
	}	
	
}
